#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "cJSON.h"
#include <openssl/md5.h>

#define N 4096
extern char mdString[33];
#define filePath1 "./node.json"
#define filePath2 "./node.zip"
int trans_success;
char received_md5[33];
char new_md5[33];

void update_md5(const char *file_md5) {
    // 1. 打开并读取文件
    FILE *fp = fopen(filePath1, "r");
    if (!fp) {
        perror("Failed to open node.json");
        return;
    }

    // 获取文件大小
    fseek(fp, 0, SEEK_END);
    long size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    // 分配内存并读取文件内容
    char *json_str = malloc(size + 1);
    if (!json_str) {
        perror("Memory allocation failed");
        fclose(fp);
        return;
    }
    fread(json_str, 1, size, fp);
    json_str[size] = '\0';
    fclose(fp);

    // 2. 解析JSON
    cJSON *root = cJSON_Parse(json_str);
    if (!root) {
        fprintf(stderr, "JSON parse error: %s\n", cJSON_GetErrorPtr());
        free(json_str);
        return;
    }

    // 3. 处理md5字段
    cJSON *md5_item = cJSON_GetObjectItem(root, "md5");
    if (md5_item) {
        // 如果已存在md5字段，更新其值
        free(md5_item->valuestring);
        md5_item->valuestring = strdup(file_md5);
        printf("Updated existing MD5 field\n");
        
        // 从原位置移除md5字段（使用替代方法）
        cJSON_DeleteItemFromObject(root, "md5");
        md5_item = cJSON_CreateString(file_md5);
        md5_item->string = strdup("md5");
    } else {
        // 创建新的md5字段
        md5_item = cJSON_CreateString(file_md5);
        md5_item->string = strdup("md5");
        printf("Added new MD5 field\n");
    }

    // 4. 将md5字段插入到version后面（使用替代方法）
    cJSON *version_item = cJSON_GetObjectItem(root, "version");
    if (version_item) {
        // 手动操作链表插入
        cJSON *after_version = version_item->next;
        version_item->next = md5_item;
        md5_item->prev = version_item;
        md5_item->next = after_version;
        if (after_version) {
            after_version->prev = md5_item;
        }
        printf("Inserted MD5 after version field\n");
    } else {
        // 如果没有version字段，添加到对象末尾
        cJSON_AddItemToObject(root, "md5", md5_item);
        printf("Version field not found, added MD5 to end\n");
    }

    // 5. 写回文件
    fp = fopen(filePath1, "w");
    if (!fp) {
        perror("Failed to write node.json");
    } else {
        char *updated = cJSON_Print(root);
        fwrite(updated, 1, strlen(updated), fp);
        fclose(fp);
        free(updated);
    }

    // 6. 释放资源
    cJSON_Delete(root);
    free(json_str);
}
void calculate_md5(const char *filename, char *md5_result)
{
    // 1. 以二进制模式打开文件
    FILE *file = fopen(filename, "rb");
    if (!file)
    {
        perror("文件打开失败");
        return;
    }

    // 2. 初始化MD5上下文结构
    MD5_CTX md5_context;
    MD5_Init(&md5_context);

    // 3. 定义文件读取缓冲区
    unsigned char buffer[1024];
    size_t bytes_read;

    // 4. 循环读取文件内容并更新MD5计算
    while ((bytes_read = fread(buffer, 1, 1024, file)) > 0)
    {
        MD5_Update(&md5_context, buffer, bytes_read);
    }

    // 5. 准备存储二进制MD5结果的数组
    unsigned char digest[MD5_DIGEST_LENGTH]; // MD5_DIGEST_LENGTH=16

    // 6. 完成计算，获取最终结果
    MD5_Final(digest, &md5_context);

    // 7. 关闭文件
    fclose(file);

    // 8. 将二进制MD5转换为十六进制字符串
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++)
    {
        // 每个字节转换为2个十六进制字符
        sprintf(&md5_result[i * 2], "%02x", (unsigned int)digest[i]);
    }
    // 9. 添加字符串结束符
    md5_result[MD5_DIGEST_LENGTH * 2] = '\0'; // MD5结果为32字符
}

int main(int argc, char const *argv[])
{
    int broadfd;

    // 创建一个socket文件描述符
    broadfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (broadfd < 0)
    {
        perror("sock err");
        return -1;
    }
    // 设置地址重用
    int reuse = 1;
    if (setsockopt(broadfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        perror("setsockopt(SO_REUSEADDR) failed");
        close(broadfd);
        return -1;
    }
    // 绑定套接字(ip+port)
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8888); // 端口号
    addr.sin_addr.s_addr = INADDR_ANY;

    int addrlen = sizeof(addr);

    if (bind(broadfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }

    ssize_t len;
    char buf[N] = {0};
    struct sockaddr_in cliaddr;

    // 接收"messsage"搜索包
    bzero(buf, N);
    len = recvfrom(broadfd, buf, N, 0, (struct sockaddr *)&cliaddr, &addrlen);
    printf("recv success\n");
    printf("ip: %s, port: %d, data: %s\n", inet_ntoa(cliaddr.sin_addr),
           ntohs(cliaddr.sin_port), buf);
    // 判断是否是本公司产品：收到的数据是否"message"
    if (strcmp(buf, "message") != 0)
    {
        printf("not my message\n");
        return -1;
    }

    // 回复yes，告诉软件，我收到了搜索协议，并且回复地址
    sendto(broadfd, "yes", 4, 0, (struct sockaddr *)&cliaddr, addrlen);
    printf("send yes success\n");
    // 变身为TCP服务器，准备接收软件的升级文件
    int tcpfd = socket(AF_INET, SOCK_STREAM, 0);
    if (tcpfd < 0)
    {
        perror("sock err");
        return -1;
    }
    // 设置地址重用
    if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        perror("setsockopt(SO_REUSEADDR) failed");
        close(tcpfd);
        return -1;
    }
    if (bind(tcpfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }

    // 监听套接字
    if (listen(tcpfd, 5) < 0)
    {
        perror("listen err");
        return -1;
    }

    // 接收客户端的连接
    printf("wait client connect\n");
    int clifd;

    // 接收对端的地址
    clifd = accept(tcpfd, NULL, NULL);
    if (clifd < 0)
    {
        perror("accept err");
        return -1;
    }
    printf("clientfd:%d\n", clifd);
    printf("new cononect coming\n");
    char buf1[N] = {0};
    // 接收判断type，来获取设备信息
    cJSON *json;
    while (1)
    {
        len = recv(clifd, buf, N, 0);
        if (len > 0)
        {
            printf("recv:%s\n", buf);
            // 解析 JSON 数据
            json = cJSON_Parse(buf);
            if (json == NULL)
            {
                printf("Error before: %s\n", cJSON_GetErrorPtr());
            }
            else
            {
                // 反序列化 JSON 对象
                cJSON *type = cJSON_GetObjectItem(json, "type");
                if (type->valueint == 0)
                {
                    cJSON *request = cJSON_GetObjectItem(json, "request");
                    if (type == NULL || request == NULL)
                    {
                        printf("JSON object missing 'type' or 'request'\n");
                        cJSON_Delete(json);
                        continue;
                    }

                    // 打印解析出的 JSON 对象
                    printf("{\n");
                    printf("\ttype: %d\n", type->valueint);
                    printf("\trequest: %s\n", request->valuestring);
                    printf("}\n");

                    // 回复
                    //   cJSON *json = cJSON_CreateObject();
                    // 创建一个JSON对象
                    cJSON *root = cJSON_CreateObject();

                    // 添加一个整数类型的字段
                    cJSON_AddNumberToObject(root, "type", 0);

                    // 创建一个嵌套的对象
                    cJSON *data = cJSON_CreateObject();
                    cJSON_AddStringToObject(data, "mqtt_address", "192.168.1.5");
                    cJSON_AddStringToObject(data, "mqtt_port", "1883");

                    // 将嵌套对象添加到根对象中
                    cJSON_AddItemToObject(root, "data", data);

                    // 将JSON对象转换为字符串
                    char *jsonString = cJSON_Print(root);
                    send(clifd, jsonString, strlen(jsonString), 0);
                    cJSON_Delete(root);
                    free(jsonString);
                }

                if (type->valueint == 1)
                {
                    cJSON *data = cJSON_GetObjectItem(json, "data");
                    cJSON *ver = cJSON_GetObjectItem(data, "ver");
                    cJSON *fileName = cJSON_GetObjectItem(data, "file_name");
                    cJSON *fileLen = cJSON_GetObjectItem(data, "file_len");
                    cJSON *md5 = cJSON_GetObjectItem(data, "md5");
                    if (ver == NULL || fileName == NULL || fileLen == NULL || md5 == NULL)
                    {
                        printf("JSON object missing 'ver' or 'file_name' or 'file_len' or 'md5'\n");
                        cJSON_Delete(json);
                        continue;
                    }
                    printf("{\n");
                    printf("\t\"ver\": %s\n", ver->valuestring);

                    printf("\t\"fileName\": %s\n", fileName->valuestring);
                    printf("\t\"fileLen\": %d\n", fileLen->valueint);
                    printf("\t\"md5\": %s\n", md5->valuestring);
                    printf("}\n");

                    /* 1. 创建根对象 {"type":1,"data":{...}} */
                    cJSON *root1 = cJSON_CreateObject();

                    /* 2. 添加 "type":1 */
                    cJSON_AddNumberToObject(root1, "type", 1);

                    /* 3. 创建 "data" 子对象 {"update":true} */
                    cJSON *newdata = cJSON_CreateObject();
                    cJSON_AddBoolToObject(newdata, "update", cJSON_True); // true
                    cJSON_AddItemToObject(root1, "data", newdata);

                    /* 4. 序列化为字符串并打印 */
                    char *json_str = cJSON_Print(root1);
                    send(clifd, json_str, strlen(json_str), 0);
                    printf("Serialized JSON:\n%s\n", json_str);

                    /* 5. 释放内存 */
                    cJSON_Delete(root1);
                    free(json_str);

                    // 创建一个新的filesocket，绑定后与qt端进行文件传输
                    int filesock = socket(AF_INET, SOCK_STREAM, 0);
                    if (filesock < 0)
                    {
                        perror("sock err");
                        return -1;
                    }
                    // 绑定
                    struct sockaddr_in addr;
                    addr.sin_family = AF_INET;
                    addr.sin_port = htons(8001);
                    addr.sin_addr.s_addr = INADDR_ANY;
                    // 设置地址重用
                    if (setsockopt(filesock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
                    {
                        perror("setsockopt(SO_REUSEADDR) failed");
                        close(filesock);
                        return -1;
                    }
                    if (bind(filesock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
                    {
                        perror("bind err");
                        return -1;
                    }
                    printf("filesock:%d\n", filesock);

                    // 监听
                    if (listen(filesock, 5) < 0)
                    {
                        perror("listen err");
                        return -1;
                    }
                    // 接收客户端的连接
                    int clifilesock = accept(filesock, NULL, NULL);
                    if (clifilesock < 0)
                    {
                        perror("accept err");
                        return -1;
                    }
                    // 接收文件

                    // 写入文件
                    // 接收文件
                    FILE *fp = fopen(filePath2, "wb");
                    if (fp == NULL)
                    {
                        perror("fopen err");
                        close(clifilesock);
                        close(filesock);
                        continue;
                    }

                    char file_buf[4096];
                    ssize_t total_len = 0;
                    ssize_t len;
                    while (1)
                    {
                        len = recv(clifilesock, file_buf, sizeof(file_buf), 0);
                        if (len > 0)
                        {
                            // 正常写入文件
                            size_t written = fwrite(file_buf, 1, len, fp);
                            if (written != len)
                            {
                                perror("fwrite error");
                                break; // 直接退出循环
                            }
                            total_len += len;
                        }
                        else if (len == 0)
                        {
                            printf("Connection closed by peer\n");
                            break; // 对端关闭连接
                        }
                        else
                        {
                            perror("recv error");
                            break; // 发生错误
                        }
                    }
                    // MD5校验（需实现md5计算函数）

                    close(filesock);
                    fclose(fp);
                    close(clifilesock);
                    // 文件接收完成后解压
                    if (total_len == fileLen->valueint)
                    {
                        calculate_md5(filePath2, received_md5); // 计算接收文件的MD5
                        printf("Received MD5: %s\n", received_md5);
                        printf("Expected MD5: %s\n", md5->valuestring);
                        // 比较MD5值
                        if (strcmp(received_md5, md5->valuestring) == 0)
                        {
                            trans_success = cJSON_True;
                        }
                        else
                        {
                            printf("MD5 checksum mismatch. File may be corrupted.\n");
                            trans_success = cJSON_False;
                        }
                        printf("File received successfully, starting unzip...\n");
                        int ret = system("unzip -o ./node.zip -d ./"); // 解压文件
                        if (ret != 0)
                        {
                            printf("Unzip failed with code %d\n", ret);
                        }
                        else
                        {
                            printf("Unzip completed successfully\n");
                        }

                        // 删除压缩包
                        remove(filePath2);
                        // remove(filePath1);
                        printf("Received file: %s, size: %zd bytes\n", fileName->valuestring, total_len);
                        // 文件接收完成后发送传输结果(type=2)
                        if (total_len == fileLen->valueint)
                        {
                            printf("File received successfully\n");
                        }
                        else
                        {
                            printf("File size mismatch\n");
                        }
                        calculate_md5(filePath1, new_md5);
                        update_md5(new_md5);
                        printf("new_md5:%s\n",new_md5);
                    }

                    cJSON *trans_result = cJSON_CreateObject();
                    cJSON_AddNumberToObject(trans_result, "type", 2);
                    cJSON *trans_data = cJSON_CreateObject();

                    cJSON_AddBoolToObject(trans_data, "trans_success", trans_success); // 根据实际传输结果设置
                    cJSON_AddItemToObject(trans_result, "data", trans_data);

                    char *trans_json = cJSON_Print(trans_result);
                    send(clifd, trans_json, strlen(trans_json), 0);
                    printf("Sent transmission result: %s\n", trans_json);

                    cJSON_Delete(trans_result);
                    free(trans_json);

                    // 模拟固件升级过程
                    printf("Starting firmware update...\n");
                    sleep(2); // 模拟升级耗时

                    // 发送升级结果(type=3)

                    cJSON *update_result = cJSON_CreateObject();
                    cJSON_AddNumberToObject(update_result, "type", 3);

                    cJSON *update_data = cJSON_CreateObject();
                    cJSON_AddBoolToObject(update_data, "update_success", cJSON_True); // 根据实际升级结果设置
                    cJSON_AddItemToObject(update_result, "data", update_data);

                    char *update_json = cJSON_Print(update_result);
                    send(clifd, update_json, strlen(update_json), 0);
                    printf("Sent update result: %s\n", update_json);

                    cJSON_Delete(update_result);
                    free(update_json);
                }
                if (type->valueint == 2)
                {
                    cJSON *data = cJSON_GetObjectItem(json, "data");
                    cJSON *trans_success = cJSON_GetObjectItem(data, "trans_success");

                    if (trans_success && trans_success->type == cJSON_True)
                    {
                        printf("Client confirmed file transmission success\n");
                    }
                    else
                    {
                        printf("Client reported file transmission failure\n");
                    }
                }
                if (type->valueint == 3)
                {
                    // 处理客户端对升级结果的确认
                    cJSON *data = cJSON_GetObjectItem(json, "data");
                    cJSON *update_success = cJSON_GetObjectItem(data, "update_success");

                    if (update_success && update_success->type == cJSON_True)
                    {
                        printf("Client confirmed firmware update success\n");
                    }
                    else
                    {
                        printf("Client reported firmware update failure\n");
                    }
                }

                // 释放 JSON 对象
                cJSON_Delete(json);
            }
        }
    }

    close(broadfd);
    close(tcpfd);
    close(clifd);
    return 0;
}
